//! 处理字符串的工具。
//!
use crate::error::Error;
use base64::Engine;
use crypto::{digest::Digest, md5::Md5, sha1::Sha1};
use rustc_serialize::hex::{FromHex, ToHex};

/// 类似windows自带的记事本等软件，在保存一个utf-8编码的文件时，会在文件开始的地方插入三个不可见的字符
/// 用于让记事本等编辑器识别这个文件是否以utf-8编码。
pub const BOM: [u8; 3] = [0xEF, 0xBB, 0xBF];

/// 匹配 <xxx>
pub const PHTML: &'static str = "<(?P<html>[^>]+)>";

/// 匹配html的注释
pub const PCOMMENT: &'static str = "(?P<comment>.*?)";

/// 匹配 script
pub const PSCRIPT: &'static str = "(?P<script><script [^>]*?>[\\s\\S]*?</script>)";

/// 匹配style css
pub const PSTYLE: &'static str = "(?P<style><style[^>]*?>[\\s\\S]*?</style>])";

/// 匹配<title>
pub const PTITLE: &'static str = "(?P<title><title>(.+?)</title>)";

/// 匹配letter 或者 digit
pub const PLETTERORDIGIT: &'static str = "(?P<letter_digit>^\\w*$)";

/// 匹配letter
pub const PLETTER: &'static str = "(?P<letter>^[A-Za-z]*$)";

/// 匹配数字
pub const PDIGIT: &'static str = "(?P<digit>^\\d*$)";

/// 匹配中文
pub const PCHINESE: &'static str = "(?P<chinese>[\\u4e00-\\u9fa5]+)";

/// 匹配ID
pub const PID: &'static str = "(?P<id>[\\w\\s\\_\\.\\,]*)";

/// 求一个字符串的md5，并以hex形式展现
pub fn md5_hex(src: &str) -> String {
    let mut md5 = Md5::new();
    md5.input(src.as_bytes());
    md5.result_str()
}

/// 求一个字符串的sha1， 并以hex的形式展现
pub fn sha1_hex(src: &str) -> String {
    let mut sha1 = Sha1::new();
    sha1.input(src.as_bytes());
    sha1.result_str()
}

/// 求一个字符串的md5，并以base64的形式展现
pub fn md5_base64(src: &str) -> String {
    let mut md5 = Md5::new();
    md5.input(src.as_bytes());
    let mut md5_byte: Vec<u8> = Vec::new();
    md5.result(&mut md5_byte);
    base64::engine::general_purpose::STANDARD.encode(md5_byte)
}

/// 从一个md5的hex形式的字符串变成base64形式的字符串
pub fn md5_base64_from_hex(md5_hex: &str) -> Result<String, Error> {
    let ret = md5_hex.from_hex()?;
    Ok(base64::engine::general_purpose::STANDARD.encode(ret))
}

/// 从一个md5的base64形式变成hex形式
pub fn md5_hex_from_base64(base64_str: &str) -> Result<String, Error> {
    let data = base64::prelude::BASE64_STANDARD.decode(base64_str.as_bytes())?;
    Ok(data.to_hex())
}

/// byte数组转换成2进制字符形式 00001111, 0101110
pub fn byte_to_binary(bs: &[u8]) -> String {
    // 一个u8用8个字符表示
    let length = bs.len();
    let mut cs: Vec<u8> = vec![0; length * 9];
    for i in 0..length {
        let b = bs[i];
        let j = i * 9;
        cs[j] = if (b >> 7) & 0x1 == 1 { 49 } else { b'0' };
        cs[j + 1] = if (b >> 6) & 0x1 == 1 { 49 } else { b'0' };
        cs[j + 2] = if (b >> 5) & 0x1 == 1 { 49 } else { b'0' };
        cs[j + 3] = if (b >> 4) & 0x1 == 1 { 49 } else { b'0' };
        cs[j + 4] = if (b >> 3) & 0x1 == 1 { 49 } else { b'0' };
        cs[j + 5] = if (b >> 2) & 0x1 == 1 { 49 } else { b'0' };
        cs[j + 6] = if (b >> 1) & 0x1 == 1 { 49 } else { b'0' };
        cs[j + 7] = if b & 0x1 == 1 { 49 } else { b'0' };
        cs[j + 8] = b',';
    }
    let _ = cs.pop();
    unsafe { String::from_utf8_unchecked(cs) }
}

/// 字节数组转换成空格分隔的hex的字符串
pub fn byte_array_to_hex_string(bs: &[u8]) -> String {
    let mut ret = String::default();
    for b in bs {
        let b_str = format!("{:2x}", b);
        ret.push_str(&b_str);
        ret.push(' ');
    }
    let _ = ret.pop();
    ret
}

pub fn is_utf8(bs: &[u8]) -> bool {
    !String::from_utf8(bs.to_vec()).is_err()
}
